//
//  UIControl.swift
//  covermedia
//
//  Created by listen on 16/5/9.
//  Copyright © 2016年 covermedia. All rights reserved.
//

import UIKit

/// 扩展：支持block方式处理
private var controlBlockKey: Void?
public extension UIControl {
    class CMControlBlock: NSObject {
        var event:UIControlEvents
        var block:((_:UIControl?)->Void)?
        weak var sender:UIControl?
        
        init(block:((_:UIControl?)->Void)? , event:UIControlEvents, sender:UIControl) {
            self.block = block
            self.event = event
            self.sender = sender
        }
        
        func invoke() {
            self.block?(sender)
        }
    }
    fileprivate var _controllBlocks: [CMControlBlock] {
        get {
            return (objc_getAssociatedObject(self, &controlBlockKey) as? [CMControlBlock]) ?? []
        }
        set(newValue) {
            objc_setAssociatedObject(self, &controlBlockKey, newValue,.OBJC_ASSOCIATION_RETAIN_NONATOMIC);
        }
    }
    
    /**
     添加处理 event 的block(默认删除原来的event处理block)
     
     - parameter event: event
     - parameter block: 处理event block的
     */
    public func addBlock(forEvent event:UIControlEvents, block:((_:UIControl?)->Void)?) {
        self.addBlock(forEvent: event, removePreEvent: true, block: block)
    }
    
    /**
     添加处理 event 的block
     
     - parameter event:          event
     - parameter removePreEvent: 是否删除原来的event处理block: true删除 false不删除
     - parameter block:          处理event 对应的block
     */
    public func addBlock(forEvent event:UIControlEvents, removePreEvent:Bool, block:((_:UIControl?)->Void)?) {
        if removePreEvent {
            removeAllBlocks(forEvent: event)
        }
        
        let block = CMControlBlock.init(block: block, event: event, sender: self)
        _controllBlocks.append(block)
        self.addTarget(block, action: #selector(CMControlBlock.invoke), for: event)
    }
    /**
     删除event相关的block处理方法
     
     - parameter event: event
     */
    public func removeAllBlocks(forEvent event:UIControlEvents) {
        _controllBlocks = _controllBlocks.filter { (b) -> Bool in
            return b.event != event
        }
    }
}


public protocol CMControlActionHandler:class {
    /// 处理 control action
    ///
    /// - Parameters:
    ///   - action: action name
    ///   - event: event type
    ///   - sender: event sender
    ///   - extData: ext data
    /// - Returns: return true, event will be consumed(terminate), false will forword to next responser
    func handle(action:String, event:UIControlEvents, sender:UIResponder?, extData:Any?) -> Bool
    
    /// 转发control action 中间层需向上传递数据
    ///
    /// - Parameters:
    ///   - action: action name
    ///   - event: event type
    ///   - sender: event sender
    /// - Returns: (target responser, extdata pass to target responser) if responser not nil, will forword event to it
    func forward(action:String, event:UIControlEvents, sender:UIResponder?) -> (UIResponder, Any?)?
}

// MARK: - 缺省实现
public extension CMControlActionHandler {
    public func forward(action:String, event:UIControlEvents, sender:UIResponder?) -> (UIResponder, Any?)? {
        return nil
    }
}

// 扩展 UIControl：支持 根据ation name来处理
private var controlActionKey:Void?
public extension UIControl {
    /// controll action类: 用于记录event处理
    class CMControlAction:NSObject {
        var action:String
        var event:UIControlEvents
        weak var sender:UIResponder?
        weak var data:AnyObject?
        
        init(action:String, event:UIControlEvents, sender:UIView, data:AnyObject?) {
            self.action = action
            self.event = event
            self.sender = sender
            self.data = data
        }
        
        func invoke() {
            var extData:Any? = self.data
            var nextResponder:UIResponder? = sender
            while nextResponder != nil {
                if let handler = nextResponder as? CMControlActionHandler {
                    if handler.handle(action: action, event: event, sender: sender, extData: extData) {
                        return
                    } else if let res = handler.forward(action: action, event: event, sender: sender) {
                        extData = res.1
                        /// 如果 target 是自身，则不处理，仅使用 extData
                        if handler !== res.0 {
                            nextResponder = res.0
                            continue
                        }
                    }
                }
                nextResponder = nextResponder?.next
            }
        }
    }
    
    fileprivate var _controllActions: [CMControlAction] {
        get {
            return (objc_getAssociatedObject(self, &controlActionKey) as? [CMControlAction]) ?? []
        }
        set(newValue) {
            objc_setAssociatedObject(self, &controlActionKey, newValue,.OBJC_ASSOCIATION_RETAIN_NONATOMIC);
        }
    }
    
    /// 添加action处理
    /// 对于event发生时候，按照响应链事件传递给实现 CMControlActionHandler 的 nextResponder，直到event被处理
    ///
    /// - Parameters:
    ///   - action: action name
    ///   - event: event anme
    ///   - data: data pass to
    public func addAction(action:String, for event:UIControlEvents, data:Any? = nil) {
        let pre = _controllActions.filter { (a) -> Bool in
            return a.action == action && a.event == event
        }
        if pre.isEmpty {
            let action = CMControlAction.init(action: action, event: event, sender: self, data: data as AnyObject?)
            _controllActions.append(action)
            self.addTarget(action, action: #selector(CMControlAction.invoke), for: event)
        }
    }
    
    /**
     删除action 处理 event
     
     - parameter action: action name
     - parameter event:  event name
     */
    public func removeAction(action:String, for event:UIControlEvents) {
        _controllActions = _controllActions.filter { (a) -> Bool in
            return !(a.action == action && a.event == event)
        }
    }
}
